home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 April: Mac OS SDK / Dev.CD Apr 98 SDK1.toast / Development Kits (Disc 1) / QuickDraw 3D / Windows files / Q3WinSDK.exe / QD3DSDK / Samples / Win32Sample / 3DShell.c next >
Encoding:
C/C++ Source or Header  |  1996-12-20  |  35.7 KB  |  1,112 lines

  1. #include <windows.h>        // required for all Windows applications
  2. #include "resource.h"        // Windows resource IDs
  3. #include "3dshell.h"        // specific to this program
  4. #include <stdio.h>
  5.  
  6. #include "Box3DSupport.h"
  7.  
  8. HINSTANCE hInst;              // current instance
  9.  
  10. DocumentPtr        gDocument = NULL;
  11.  
  12. char szAppName[] = "QuickDraw 3D Demo";        // The name of this application
  13. char szTitle[]   = "QuickDraw 3D Demo";        // The title bar text
  14. COLORREF customColors[16] = { 0L };            // for use by choosecolor dialog
  15.  
  16. typedef enum tStorageMethod
  17. {
  18.     kStorageUnixFile,
  19.     kStorageUnixPath,
  20.     kStorageWin32Handle,
  21.     kStorageWin32MMFile
  22. } tStorageMethod;
  23.  
  24. void        OpenModelFile( tStorageMethod );
  25. void        SaveModelFile( tStorageMethod storageMethod, TQ3FileMode dstFileMode );
  26.  
  27. TQ3Status    BrowseForPathName(char *inPathName, BOOLEAN fOpen);
  28.  
  29. void        UpdateFrame(BOOLEAN step);
  30.  
  31. BOOL        InitDocumentData( DocumentPtr theDocument, HWND inWindow );
  32. void        DisposeDocumentData( DocumentPtr theDocument);
  33. void        DisposeRenderingData( DocumentPtr theDocument);
  34. TQ3Status    DocumentDraw3DData( DocumentPtr theDocument );
  35. int            Speedometer_ClockFrame( void );
  36.  
  37. TQ3Status    DocumentNewWindowSize(DocumentPtr theDocument, unsigned long width, unsigned long height);
  38.  
  39. TQ3Status    PaintDocumentWindow(DocumentPtr theDocument);
  40.  
  41. TQ3Status    GetToolBarPosition(DocumentPtr theDocument, unsigned long *x, unsigned long *y);
  42. TQ3Status    GetToolBarSize(DocumentPtr theDocument, unsigned long *width, unsigned long *height);
  43.  
  44. void        InitQD3DMenu ( HWND hwnd );
  45.  
  46. void        MyErrorHandler(TQ3Error firstError, TQ3Error lastError, long refCon); 
  47.  
  48. #define REFERROR 00L
  49. #define REFWARNING 01L
  50. #define REFNOTICE 02L
  51.  
  52. static void StartTimer( void );
  53. static void StopTimer( void );
  54.  
  55. VOID CALLBACK TimerProc( HWND, UINT, UINT, DWORD );    
  56. UINT gTimer;
  57. #define MILLSPERTICK 10  // milliseconds per timer tick
  58.  
  59.  
  60. int CALLBACK WinMain(
  61.         HINSTANCE hInstance,
  62.         HINSTANCE hPrevInstance,
  63.         LPSTR lpCmdLine,
  64.         int nCmdShow)
  65. {
  66.         MSG msg;
  67.         HANDLE hAccelTable;
  68.  
  69.         if (!InitApplication(hInstance)) 
  70.         {
  71.             return (FALSE);    
  72.         }
  73.  
  74.         if (!InitInstance(hInstance, nCmdShow)) 
  75.         {
  76.             return (FALSE);
  77.         }
  78.  
  79.         hAccelTable = LoadAccelerators (hInstance, MAKEINTRESOURCE(IDR_GENERIC));
  80.  
  81.         StartTimer();
  82.         while (GetMessage(&msg, NULL, 0, 0)) {
  83.             if (!TranslateAccelerator (msg.hwnd, hAccelTable, &msg)) {
  84.                 TranslateMessage(&msg);
  85.                 DispatchMessage(&msg);
  86.             }
  87.         }
  88.         StopTimer();
  89.  
  90.         return (msg.wParam); // Returns the value from PostQuitMessage
  91. }
  92.  
  93. void UpdateFrame(BOOLEAN step)
  94. {
  95.     TQ3Matrix4x4    tmp;
  96.     RECT            aWinRect;
  97.     BOOL            aResult;
  98.     if( step )
  99.     {
  100.         Q3Matrix4x4_SetRotate_XYZ(&tmp, 0.05F, 0.05F, 0.05F);
  101.         Q3Matrix4x4_Multiply(&gDocument->fRotation, &tmp, &gDocument->fRotation);
  102.     }
  103.     aResult = GetClientRect(gDocument->fWindow, (LPRECT)&aWinRect);
  104.     aWinRect.bottom = aWinRect.top + gDocument->fHeight;
  105.     aResult = InvalidateRect(gDocument->fWindow, &aWinRect, FALSE);    
  106. }
  107.  
  108.  
  109. BOOL InitApplication(HINSTANCE hInstance)
  110. {
  111.         WNDCLASS  wc;
  112.  
  113.         wc.style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;    /* CS_OWNDC is required to support the Win32DC Draw context */
  114.         wc.lpfnWndProc   = (WNDPROC)WndProc;       
  115.         wc.cbClsExtra    = 0;                      
  116.         wc.cbWndExtra    = 0;                     
  117.         wc.hInstance     = hInstance;             
  118.         wc.hIcon         = LoadIcon (hInstance, MAKEINTRESOURCE(IDI_APP)); 
  119.         wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  120.         wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
  121.         wc.lpszMenuName  = MAKEINTRESOURCE(IDR_GENERIC); 
  122.         wc.lpszClassName = szAppName;              
  123.  
  124.         return (RegisterClass(&wc));
  125. }
  126.  
  127. BOOL InitInstance(
  128.         HINSTANCE       hInstance,
  129.         int             nCmdShow)
  130. {
  131.         HWND            hWnd; 
  132.  
  133.         hInst = hInstance; 
  134.         hWnd = CreateWindowEx(
  135.                 WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE,
  136.                 szAppName,          
  137.                 szTitle,             
  138.                 WS_OVERLAPPEDWINDOW, 
  139.                 25, 25, 640, 530,      // fixed size windows
  140.                 NULL,                
  141.                 NULL,                
  142.                 hInstance,           
  143.                 NULL                 
  144.         );
  145.  
  146.         if (!hWnd) 
  147.         {
  148.             return (FALSE);
  149.         }
  150.  
  151.  
  152.         ShowWindow(hWnd, nCmdShow); 
  153.         UpdateWindow(hWnd);        
  154.  
  155.         return (TRUE);             
  156.  
  157. }
  158.  
  159. static void StartTimer( void )
  160. {
  161.     if( gDocument && kQ3True == gDocument->spin)
  162.         gTimer = SetTimer( NULL, 0, MILLSPERTICK, (TIMERPROC) TimerProc );
  163. }
  164.  
  165. static void StopTimer( void )
  166. {
  167.     if( gDocument && kQ3True == gDocument->spin)
  168.         KillTimer( NULL, gTimer );
  169. }
  170.  
  171. VOID CALLBACK TimerProc(
  172.     HWND hwnd,    // handle of window for timer messages 
  173.     UINT uMsg,    // WM_TIMER message
  174.     UINT idEvent,    // timer identifier
  175.     DWORD dwTime     // current system time
  176.    )    
  177. {
  178.     if( kQ3True == gDocument->spin)
  179.         UpdateFrame(TRUE);
  180. }
  181.  
  182.  
  183. LRESULT CALLBACK WndProc(
  184.                 HWND hWnd,        
  185.                 UINT message,      
  186.                 WPARAM uParam,     
  187.                 LPARAM lParam)   
  188. {
  189.         int wmId, wmEvent;
  190.         TQ3Status    aStatus;
  191.         PAINTSTRUCT PaintStruct;
  192.  
  193.         switch (message) 
  194.         {
  195.             case WM_COMMAND:
  196.  
  197.                 wmId    = LOWORD(uParam);
  198.                 wmEvent = HIWORD(uParam);
  199.  
  200.                 switch (wmId) 
  201.                 {
  202.                     case IDM_ABOUT:
  203.                         StopTimer();
  204.                         DialogBox(hInst,          
  205.                                 MAKEINTRESOURCE(IDD_ABOUTBOX),
  206.                                 hWnd,                 
  207.                                 (DLGPROC)About);
  208.                         StartTimer();
  209.                         break;
  210.                     case ID_FILE_OPEN_WIN32:
  211.                         StopTimer();
  212.                         OpenModelFile(kStorageWin32Handle);
  213.                         StartTimer();
  214.                         break;
  215.                     case ID_FILE_OPEN_MMF:
  216.                         StopTimer();
  217.                         OpenModelFile(kStorageWin32MMFile);
  218.                         StartTimer();
  219.                         break;
  220.                     case ID_FILE_OPEN_UNIX:
  221.                         StopTimer();
  222.                         OpenModelFile(kStorageUnixFile);
  223.                         StartTimer();
  224.                         break;
  225.                     case ID_FILE_OPEN_PATH:
  226.                         StopTimer();
  227.                         OpenModelFile(kStorageUnixPath);
  228.                         StartTimer();
  229.                         break;
  230.                     case ID_FILE_SAVE_WIN32:
  231.                         StopTimer();
  232.                         SaveModelFile(kStorageWin32Handle, kQ3FileModeNormal );
  233.                         StartTimer();
  234.                         break;
  235.                     case ID_FILE_SAVE_WIN32_TEXT:
  236.                         StopTimer();
  237.                         SaveModelFile(kStorageWin32Handle, kQ3FileModeText );
  238.                         StartTimer();
  239.                         break;
  240.                     case ID_FILE_SAVE_UNIX:
  241.                         StopTimer();
  242.                         SaveModelFile(kStorageUnixFile, kQ3FileModeNormal );
  243.                         StartTimer();
  244.                         break;
  245.                     case ID_FILE_SAVE_UNIX_TEXT:
  246.                         StopTimer();
  247.                         SaveModelFile(kStorageUnixFile, kQ3FileModeText );
  248.                         StartTimer();
  249.                         break;
  250.                     case ID_FILE_SAVE_PATH:
  251.                         StopTimer();
  252.                         SaveModelFile(kStorageUnixPath, kQ3FileModeNormal );
  253.                         StartTimer();
  254.                         break;
  255.                     case ID_FILE_SAVE_PATH_TEXT:
  256.                         StopTimer();
  257.                         SaveModelFile(kStorageUnixPath, kQ3FileModeText );
  258.                         StartTimer();
  259.                         break;
  260.  
  261.                     case IDM_EXIT:
  262.                         DestroyWindow (hWnd);
  263.                         break;
  264.  
  265.                     case ID_QD3D_RENDERER_INTERACTIVE:
  266.                         if( kQ3RendererTypeInteractive != gDocument->rendererType)
  267.                         {
  268.                             gDocument->rendererType = kQ3RendererTypeInteractive;
  269.                             DisposeRenderingData( gDocument);
  270.                             InitDocumentData( gDocument, hWnd ); 
  271.                             UpdateFrame((BOOLEAN)(kQ3True == gDocument->spin));    
  272.                         }
  273.                         break;
  274.                     
  275.                     case ID_QD3D_RENDERER_WIREFRAME:
  276.                         if( kQ3RendererTypeWireFrame != gDocument->rendererType)
  277.                         {
  278.                             gDocument->rendererType = kQ3RendererTypeWireFrame;
  279.                             DisposeRenderingData( gDocument);
  280.                             InitDocumentData( gDocument, hWnd ); 
  281.                             UpdateFrame((BOOLEAN)(kQ3True == gDocument->spin));    
  282.                         }
  283.                         break;
  284.                     
  285.                     case ID_QD3D_DRAWCONTEXT_WIN32DC:
  286.                         if( kQ3DrawContextTypeWin32DC != gDocument->drawcontextType)
  287.                         {
  288.                             gDocument->drawcontextType = kQ3DrawContextTypeWin32DC;
  289.                             DisposeRenderingData( gDocument);
  290.                             InitDocumentData( gDocument, hWnd ); 
  291.                             UpdateFrame((BOOLEAN)(kQ3True == gDocument->spin));    
  292.                         }
  293.                         break;
  294.  
  295.                     case ID_QD3D_DRAWCONTEXT_PIXMAP16BIT555:
  296.                         if(!( kQ3DrawContextTypePixmap == gDocument->drawcontextType 
  297.                             && kQ3PixelTypeRGB16 == gDocument->fPixelFormat ))
  298.                         {
  299.                             gDocument->drawcontextType = kQ3DrawContextTypePixmap;
  300.                             gDocument->fPixelFormat = kQ3PixelTypeRGB16;
  301.                             DisposeRenderingData( gDocument);
  302.                             InitDocumentData( gDocument, hWnd ); 
  303.                             UpdateFrame((BOOLEAN)(kQ3True == gDocument->spin));    
  304.                         }
  305.                         break;
  306.                     
  307.                     case ID_QD3D_DRAWCONTEXT_PIXMAP16BIT565:
  308.                         if(!( kQ3DrawContextTypePixmap == gDocument->drawcontextType 
  309.                             && kQ3PixelTypeRGB16_565 == gDocument->fPixelFormat ))
  310.                         {
  311.                             gDocument->drawcontextType = kQ3DrawContextTypePixmap;
  312.                             gDocument->fPixelFormat = kQ3PixelTypeRGB16_565;
  313.                             DisposeRenderingData( gDocument);
  314.                             InitDocumentData( gDocument, hWnd ); 
  315.                             UpdateFrame((BOOLEAN)(kQ3True == gDocument->spin));    
  316.                         }
  317.                         break;
  318.  
  319.                     case ID_QD3D_DRAWCONTEXT_PIXMAP24BIT:
  320.                         if( !(kQ3DrawContextTypePixmap == gDocument->drawcontextType 
  321.                             && kQ3PixelTypeRGB24 == gDocument->fPixelFormat ))
  322.                         {
  323.                             gDocument->drawcontextType = kQ3DrawContextTypePixmap;
  324.                             gDocument->fPixelFormat = kQ3PixelTypeRGB24;
  325.                             DisposeRenderingData( gDocument);
  326.                             InitDocumentData( gDocument, hWnd ); 
  327.                             UpdateFrame((BOOLEAN)(kQ3True == gDocument->spin));    
  328.                         }
  329.                         break;
  330.                     
  331.                     case ID_QD3D_DRAWCONTEXT_PIXMAP32BIT:
  332.                         if( !(kQ3DrawContextTypePixmap == gDocument->drawcontextType 
  333.                             && kQ3PixelTypeRGB32 == gDocument->fPixelFormat ) )
  334.                         {
  335.                             gDocument->drawcontextType = kQ3DrawContextTypePixmap;
  336.                             gDocument->fPixelFormat = kQ3PixelTypeRGB32;
  337.                             DisposeRenderingData( gDocument);
  338.                             InitDocumentData( gDocument, hWnd ); 
  339.                             UpdateFrame((BOOLEAN)(kQ3True == gDocument->spin));    
  340.                         }
  341.                         break;
  342.  
  343.                     case ID_QD3D_SPIN:
  344.                         if( kQ3True == gDocument->spin)
  345.                         {
  346.                             gDocument->spin = kQ3False;
  347.                             StopTimer();
  348.                         }
  349.                         else
  350.                         {
  351.                             gDocument->spin = kQ3True;
  352.                             StartTimer();
  353.                         }
  354.                         break;
  355.                     
  356.                     case ID_QD3D_STEP:
  357.                         if( kQ3True == gDocument->spin)
  358.                         {
  359.                             gDocument->spin = kQ3False;
  360.                             StopTimer();
  361.                         }
  362.                         UpdateFrame(TRUE);    
  363.                         break;
  364.                     
  365.                     case ID_QD3D_CLEARCOLOR:
  366.                         {
  367.                         CHOOSECOLOR cc;
  368.                         memset(&cc,0,sizeof( CHOOSECOLOR ) ); 
  369.                         cc.lStructSize = sizeof( CHOOSECOLOR ); 
  370.                         cc.hwndOwner = hWnd; 
  371.                         cc.hInstance = hInst; 
  372.                         cc.lpCustColors = customColors;
  373.                         cc.rgbResult = RGB(gDocument->clearColorR,
  374.                             gDocument->clearColorG,
  375.                             gDocument->clearColorB); 
  376.                         cc.Flags = CC_RGBINIT; 
  377.  
  378.                         if( ChooseColor( &cc ) )
  379.                         {
  380.                             TQ3DrawContextObject drawContext;
  381.                             TQ3ColorARGB q3Color;
  382.                             q3Color.a = 1.0F;
  383.                             gDocument->clearColorR = GetRValue(cc.rgbResult);
  384.                             q3Color.r = (float)gDocument->clearColorR/(float)255;
  385.                             gDocument->clearColorG = GetGValue(cc.rgbResult);
  386.                             q3Color.g = (float)gDocument->clearColorG/(float)255;
  387.                             gDocument->clearColorB = GetBValue(cc.rgbResult);
  388.                             q3Color.b = (float)gDocument->clearColorB/(float)255;
  389.                             if( gDocument->fView )
  390.                                 if( Q3View_GetDrawContext(gDocument->fView, &drawContext) )
  391.                                     Q3DrawContext_SetClearImageColor(drawContext, &q3Color); 
  392.                             UpdateFrame((BOOLEAN)(kQ3True == gDocument->spin));    
  393.                         }
  394.                         break;
  395.                         }
  396.                     default:
  397.                         return (DefWindowProc(hWnd, message, uParam, lParam));
  398.                 }
  399.                 break;
  400.  
  401.             case WM_CREATE:
  402.                 aStatus = Q3Initialize();
  403.                 if( aStatus == kQ3Failure )
  404.                     return -1;
  405.                 Q3Error_Register( MyErrorHandler, REFERROR );
  406.                 Q3Warning_Register( MyErrorHandler, REFWARNING );
  407.                 Q3Notice_Register( MyErrorHandler, REFNOTICE );
  408.                 gDocument = (DocumentPtr)malloc(sizeof(DocumentRec));
  409.                 memset( gDocument, 0, sizeof(DocumentRec) );
  410.  
  411.                 /* these are the defaults */
  412.                 gDocument->rendererType = kQ3RendererTypeInteractive;
  413.                 gDocument->drawcontextType = kQ3DrawContextTypeWin32DC;
  414.                 gDocument->spin = kQ3True;
  415.                 gDocument->clearColorR = 255;
  416.                 gDocument->clearColorG = 255;
  417.                 gDocument->clearColorB = 255;
  418.  
  419.                 if( InitDocumentData(gDocument, hWnd) == FALSE )
  420.                     return -1;
  421.                 break;
  422.  
  423.             case WM_DESTROY:  // message: window being destroyed
  424.                 PostQuitMessage(0);
  425.                 DisposeDocumentData(gDocument);
  426.                 if( gDocument )
  427.                     free(gDocument);
  428.                 gDocument = NULL;
  429.                 aStatus = Q3Exit();
  430.                 break;
  431.  
  432.             case WM_PAINT:
  433.                 BeginPaint(gDocument->fWindow, &PaintStruct);                
  434.                 DocumentDraw3DData(gDocument);
  435.                 EndPaint(gDocument->fWindow, &PaintStruct);
  436.                 break;
  437.  
  438.             case WM_INITMENU:
  439.                 InitQD3DMenu(hWnd);
  440.                 break;
  441.  
  442.             case WM_SIZE:
  443.                 {
  444.                 unsigned long width = LOWORD(lParam);  // width of client area 
  445.                 unsigned long height = HIWORD(lParam); // height of client area 
  446.  
  447.                 DocumentNewWindowSize( gDocument, width, height );
  448.                 break;
  449.                 }
  450.             default:          // Passes it on if unproccessed
  451.                     return (DefWindowProc(hWnd, message, uParam, lParam));
  452.         }
  453.         return (0);
  454. }
  455.  
  456. void InitQD3DMenu ( HWND hwnd )
  457. {
  458.     HMENU hMenu;
  459.     if( NULL == gDocument )
  460.         return;
  461.  
  462.     hMenu = GetMenu( hwnd );
  463.     if (kQ3True == gDocument->spin) 
  464.         CheckMenuItem( hMenu, ID_QD3D_SPIN, MF_BYCOMMAND | MF_CHECKED );
  465.     else
  466.         CheckMenuItem( hMenu, ID_QD3D_SPIN, MF_BYCOMMAND | MF_UNCHECKED );
  467.  
  468.     if (kQ3RendererTypeInteractive == gDocument->rendererType) 
  469.         CheckMenuItem( hMenu, ID_QD3D_RENDERER_INTERACTIVE, MF_BYCOMMAND | MF_CHECKED );
  470.     else
  471.         CheckMenuItem( hMenu, ID_QD3D_RENDERER_INTERACTIVE, MF_BYCOMMAND | MF_UNCHECKED );
  472.     
  473.     if (kQ3RendererTypeWireFrame == gDocument->rendererType) 
  474.         CheckMenuItem( hMenu, ID_QD3D_RENDERER_WIREFRAME, MF_BYCOMMAND | MF_CHECKED );
  475.     else
  476.         CheckMenuItem( hMenu, ID_QD3D_RENDERER_WIREFRAME, MF_BYCOMMAND | MF_UNCHECKED );
  477.  
  478.     if (kQ3DrawContextTypePixmap == gDocument->drawcontextType)
  479.         switch( gDocument->fPixelFormat )
  480.         {
  481.             case kQ3PixelTypeRGB16:
  482.                 CheckMenuItem( hMenu, ID_QD3D_DRAWCONTEXT_PIXMAP16BIT555, MF_BYCOMMAND | MF_CHECKED );
  483.                 CheckMenuItem( hMenu, ID_QD3D_DRAWCONTEXT_PIXMAP16BIT565, MF_BYCOMMAND | MF_UNCHECKED );
  484.                 CheckMenuItem( hMenu, ID_QD3D_DRAWCONTEXT_PIXMAP24BIT, MF_BYCOMMAND | MF_UNCHECKED );
  485.                 CheckMenuItem( hMenu, ID_QD3D_DRAWCONTEXT_PIXMAP32BIT, MF_BYCOMMAND | MF_UNCHECKED );
  486.                 break;
  487.             case kQ3PixelTypeRGB16_565:
  488.                 CheckMenuItem( hMenu, ID_QD3D_DRAWCONTEXT_PIXMAP16BIT555, MF_BYCOMMAND | MF_UNCHECKED );
  489.                 CheckMenuItem( hMenu, ID_QD3D_DRAWCONTEXT_PIXMAP16BIT565, MF_BYCOMMAND | MF_CHECKED );
  490.                 CheckMenuItem( hMenu, ID_QD3D_DRAWCONTEXT_PIXMAP24BIT, MF_BYCOMMAND | MF_UNCHECKED );
  491.                 CheckMenuItem( hMenu, ID_QD3D_DRAWCONTEXT_PIXMAP32BIT, MF_BYCOMMAND | MF_UNCHECKED );
  492.                 break;
  493.             case kQ3PixelTypeRGB24:
  494.                 CheckMenuItem( hMenu, ID_QD3D_DRAWCONTEXT_PIXMAP16BIT555, MF_BYCOMMAND | MF_UNCHECKED );
  495.                 CheckMenuItem( hMenu, ID_QD3D_DRAWCONTEXT_PIXMAP16BIT565, MF_BYCOMMAND | MF_UNCHECKED );
  496.                 CheckMenuItem( hMenu, ID_QD3D_DRAWCONTEXT_PIXMAP24BIT, MF_BYCOMMAND | MF_CHECKED );
  497.                 CheckMenuItem( hMenu, ID_QD3D_DRAWCONTEXT_PIXMAP32BIT, MF_BYCOMMAND | MF_UNCHECKED );
  498.                 break;
  499.             case kQ3PixelTypeRGB32:
  500.                 CheckMenuItem( hMenu, ID_QD3D_DRAWCONTEXT_PIXMAP16BIT555, MF_BYCOMMAND | MF_UNCHECKED );
  501.                 CheckMenuItem( hMenu, ID_QD3D_DRAWCONTEXT_PIXMAP16BIT565, MF_BYCOMMAND | MF_UNCHECKED );
  502.                 CheckMenuItem( hMenu, ID_QD3D_DRAWCONTEXT_PIXMAP24BIT, MF_BYCOMMAND | MF_UNCHECKED );
  503.                 CheckMenuItem( hMenu, ID_QD3D_DRAWCONTEXT_PIXMAP32BIT, MF_BYCOMMAND | MF_CHECKED );
  504.                 break;
  505.         }
  506.     else
  507.     {
  508.         CheckMenuItem( hMenu, ID_QD3D_DRAWCONTEXT_PIXMAP16BIT555, MF_BYCOMMAND | MF_UNCHECKED );
  509.         CheckMenuItem( hMenu, ID_QD3D_DRAWCONTEXT_PIXMAP16BIT565, MF_BYCOMMAND | MF_UNCHECKED );
  510.         CheckMenuItem( hMenu, ID_QD3D_DRAWCONTEXT_PIXMAP24BIT, MF_BYCOMMAND | MF_UNCHECKED );
  511.         CheckMenuItem( hMenu, ID_QD3D_DRAWCONTEXT_PIXMAP32BIT, MF_BYCOMMAND | MF_UNCHECKED );
  512.     }
  513.  
  514.     if (kQ3DrawContextTypeWin32DC == gDocument->drawcontextType) 
  515.         CheckMenuItem( hMenu, ID_QD3D_DRAWCONTEXT_WIN32DC, MF_BYCOMMAND | MF_CHECKED );
  516.     else
  517.         CheckMenuItem( hMenu, ID_QD3D_DRAWCONTEXT_WIN32DC, MF_BYCOMMAND | MF_UNCHECKED );
  518.  
  519.     if (kQ3DrawContextTypeDDSurface == gDocument->drawcontextType) 
  520.         CheckMenuItem( hMenu, ID_QD3D_DRAWCONTEXT_DIRECTDRAW, MF_BYCOMMAND | MF_CHECKED );
  521.     else
  522.         CheckMenuItem( hMenu, ID_QD3D_DRAWCONTEXT_DIRECTDRAW, MF_BYCOMMAND | MF_UNCHECKED );
  523.     
  524. }
  525.  
  526.  
  527. void MyErrorHandler(TQ3Error firstError, TQ3Error lastError, long refCon) 
  528.     char buf[512];
  529.     switch( refCon )
  530.     {
  531.         case REFERROR:
  532.             sprintf(buf, "QD3D ERROR %d\n", lastError); 
  533.             break;
  534.         case REFWARNING:
  535.             sprintf(buf, "QD3D WARNING %d\n", lastError); 
  536.             break;
  537.         case REFNOTICE:
  538.             sprintf(buf, "QD3D NOTICE %d\n", lastError); 
  539.             break;
  540.     }
  541.     OutputDebugString(buf); 
  542. }
  543.  
  544. char ExtFilter[] = "QuickDraw 3D Metafiles\0*.3dmf;*.3dm;*.q3d;*.qd3d\0All Files\0*.*\0\0";
  545.  
  546. // put up common dialog; fOpen == TRUE for Open, FALSE for Save As.
  547. TQ3Status    BrowseForPathName(char *inPathName, BOOLEAN fOpen) 
  548. {
  549.     OPENFILENAME aFileName;
  550.     TQ3Status     aStatus = kQ3Success;
  551.  
  552.     inPathName[0] = 0;
  553.     aFileName.lStructSize = sizeof(OPENFILENAME);
  554.     aFileName.hwndOwner = gDocument->fWindow;
  555.     aFileName.hInstance = NULL;
  556.     aFileName.lpstrFilter = ExtFilter;
  557.     aFileName.lpstrCustomFilter = NULL; 
  558.     aFileName.nMaxCustFilter = 0L; 
  559.     aFileName.nFilterIndex = 0; 
  560.     aFileName.lpstrFile = inPathName; 
  561.     aFileName.nMaxFile = 255; 
  562.     aFileName.lpstrFileTitle = NULL;    
  563.     aFileName.nMaxFileTitle = 0; 
  564.     aFileName.lpstrInitialDir = NULL;  
  565.     aFileName.lpstrTitle = NULL;    
  566.     aFileName.Flags = OFN_EXPLORER + OFN_LONGNAMES + OFN_PATHMUSTEXIST; 
  567.     if( fOpen )
  568.         aFileName.Flags += OFN_FILEMUSTEXIST;
  569.     aFileName.nFileOffset = 0; 
  570.     aFileName.nFileExtension = 0; 
  571.     aFileName.lpstrDefExt = NULL; 
  572.     aFileName.lCustData = 0; 
  573.     aFileName.lpfnHook = NULL; 
  574.     aFileName.lpTemplateName = NULL; 
  575.     if (fOpen )
  576.         if (GetOpenFileName((LPOPENFILENAME)&aFileName))
  577.             aStatus = kQ3Success;
  578.         else
  579.             aStatus = kQ3Failure;
  580.     else //saving
  581.         if (GetSaveFileName((LPOPENFILENAME)&aFileName))
  582.             aStatus = kQ3Success;
  583.         else
  584.             aStatus = kQ3Failure;
  585.  
  586.     return aStatus;
  587. }
  588.  
  589. /* Note: OpenModelFile will use different storage classes based on storageMethod flag */
  590. void        OpenModelFile( tStorageMethod storageMethod )
  591. {
  592.     #undef A3Assert
  593.     #define    A3Assert(x)        if (!(x)) goto ExitOpenModelFile
  594.  
  595.     char                pathName[MAX_PATH];
  596.     TQ3StorageObject    srcStorage = NULL;
  597.     TQ3FileObject        srcFileObject = NULL;
  598.     TQ3GroupObject        aGroup = NULL;
  599.     TQ3Object            anObject = NULL;
  600.     TQ3FileMode            srcFileMode;
  601.     TQ3GroupPosition    aPosition;
  602.     HANDLE                hFile;
  603.     TQ3Status            aStatus;
  604.     RECT                aWinRect;
  605.     BOOL                aBoolResult;
  606.     DWORD                dwFileSize;
  607.     HANDLE                hFileMap;
  608.     LPVOID                buffer;
  609.     FILE                *aFile;
  610.  
  611.  
  612.     if (BrowseForPathName(pathName, TRUE) != kQ3Success)
  613.         goto ExitOpenModelFile;
  614.     
  615.     /* Open the file and create QD3D storage object */
  616.     switch( storageMethod )
  617.     {
  618.     case kStorageWin32Handle:
  619.     // Use Win32 Handle File Types 
  620.         hFile = CreateFile(
  621.             pathName,    // pointer to name of the file 
  622.             GENERIC_READ,    // access (read-write) mode 
  623.             0,    // share mode 
  624.             NULL,    // pointer to security descriptor 
  625.             OPEN_EXISTING,    // how to create 
  626.             FILE_ATTRIBUTE_NORMAL,    // file attributes 
  627.             NULL     // handle to file with attributes to copy  
  628.         );
  629.         A3Assert(hFile != INVALID_HANDLE_VALUE);
  630.         A3Assert((srcStorage = Q3Win32Storage_New(hFile)) != NULL);
  631.         break;
  632.  
  633.     case kStorageWin32MMFile:
  634.     // Use Win32's Memory Mapped File mechanism to read 3DMF file as 
  635.     // QD3D Memory Buffer Storage Object
  636.         hFile = CreateFile(
  637.             pathName,    // pointer to name of the file 
  638.             GENERIC_READ,    // access (read-write) mode 
  639.             0,    // share mode 
  640.             NULL,    // pointer to security descriptor 
  641.             OPEN_EXISTING,    // how to create 
  642.             FILE_ATTRIBUTE_NORMAL,    // file attributes 
  643.             NULL     // handle to file with attributes to copy  
  644.         );
  645.         A3Assert(hFile != INVALID_HANDLE_VALUE);
  646.         // Create memory mapping of file
  647.         dwFileSize = GetFileSize(hFile, NULL);
  648.         // Create the file-mapping object. 
  649.         hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, dwFileSize, NULL);
  650.         if (hFileMap == NULL) 
  651.         {
  652.           CloseHandle(hFile);
  653.           A3Assert(0);
  654.         }
  655.         // Get the address where the first byte of the file is mapped into memory.
  656.         buffer = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);
  657.         if (buffer == NULL) 
  658.         {
  659.           CloseHandle(hFileMap);
  660.           CloseHandle(hFile);
  661.           A3Assert(0);
  662.         }
  663.         // Create QD3D Memory Buffer storage object
  664.         A3Assert((srcStorage = Q3MemoryStorage_NewBuffer(buffer, dwFileSize, dwFileSize)) != NULL);
  665.         break;
  666.  
  667.     case kStorageUnixFile:
  668.         aFile = fopen(pathName, "rb");
  669.         A3Assert((srcStorage = Q3UnixStorage_New(aFile)) != NULL);
  670.         break;
  671.     case kStorageUnixPath:
  672.         A3Assert((srcStorage = Q3UnixPathStorage_New(pathName)) != NULL);
  673.         break;
  674.     }
  675.  
  676.     A3Assert((srcFileObject = Q3File_New()) != NULL);
  677.     A3Assert((aStatus = Q3File_SetStorage(srcFileObject, srcStorage)) == kQ3Success);
  678.     A3Assert((aStatus = Q3File_OpenRead(srcFileObject, &srcFileMode)) == kQ3Success);
  679.     A3Assert((aGroup = Q3DisplayGroup_New()) != NULL);
  680.     while (Q3File_IsEndOfFile(srcFileObject) == kQ3False)
  681.     {
  682.         A3Assert((anObject = Q3File_ReadObject(srcFileObject)) != NULL);
  683.         A3Assert(Q3Error_Get(NULL) == kQ3ErrorNone);
  684.         if (Q3Object_IsDrawable(anObject) == kQ3True)
  685.             A3Assert((aPosition = Q3Group_AddObject(aGroup, anObject)) != NULL);
  686.         A3Assert(Q3Object_Dispose(anObject) == kQ3Success);
  687.         anObject = NULL;
  688.     }
  689.     A3Assert((Q3Object_Dispose(gDocument->fModel)) == kQ3Success);
  690.     gDocument->fModel = aGroup;
  691.     A3Assert((aStatus = Q3File_Close(srcFileObject)) == kQ3Success);
  692.     
  693.     /* Close the file system file as needed */
  694.     switch( storageMethod )
  695.     {
  696.     case kStorageWin32Handle:
  697.         CloseHandle( hFile );
  698.         break;
  699.     case kStorageWin32MMFile:
  700.         UnmapViewOfFile( buffer );
  701.         CloseHandle(hFileMap);
  702.         CloseHandle( hFile );
  703.         break;
  704.     case kStorageUnixFile:
  705.         fclose(aFile);
  706.         break;
  707.     case kStorageUnixPath:
  708.         // Nothing extra needs to be done 
  709.         break;
  710.     }
  711.  
  712.     A3Assert((aStatus = Q3Object_Dispose(srcFileObject)) == kQ3Success);
  713.     A3Assert((aStatus = Q3Object_Dispose(srcStorage)) == kQ3Success);
  714.     pvCamera_Fit(gDocument);
  715.     aBoolResult = GetClientRect(gDocument->fWindow, (LPRECT)&aWinRect);
  716.     aBoolResult = InvalidateRect(gDocument->fWindow, &aWinRect, FALSE);    
  717.  
  718. ExitOpenModelFile:
  719.     ;
  720. }
  721.  
  722.  
  723. /* Note: SaveModelFile will use different storage classes based on storageMethod flag */
  724. /* kStorageWin32MMFile is not supported */
  725. void        SaveModelFile( tStorageMethod storageMethod, TQ3FileMode dstFileMode )
  726. {
  727.     #undef A3Assert
  728.     #define    A3Assert(x)        if (!(x)) goto ExitSaveModelFile
  729.  
  730.     char                pathName[MAX_PATH];
  731.     TQ3FileObject        dstFileObject = NULL;
  732.     TQ3StorageObject    dstStorage = NULL;
  733.     TQ3ViewObject        dstView;
  734.     TQ3Status            aStatus;
  735.     TQ3ViewStatus        aViewStatus;
  736.     HANDLE                hFile;
  737.     FILE                *aFile;
  738.  
  739.     if (BrowseForPathName(pathName, FALSE) != kQ3Success)
  740.         goto ExitSaveModelFile;
  741.     
  742.     /* Open the file and create QD3D storage object */
  743.     switch( storageMethod )
  744.     {
  745.     case kStorageWin32Handle:
  746.     // Use Win32 Handle File Types 
  747.         hFile = CreateFile(
  748.             pathName,    // pointer to name of the file 
  749.             GENERIC_WRITE,    // access (read-write) mode 
  750.             0,    // share mode 
  751.             NULL,    // pointer to security descriptor 
  752.             CREATE_NEW,    // how to create 
  753.             FILE_ATTRIBUTE_NORMAL,    // file attributes 
  754.             NULL     // handle to file with attributes to copy  
  755.         );
  756.         A3Assert(hFile != INVALID_HANDLE_VALUE);
  757.         A3Assert((dstStorage = Q3Win32Storage_New(hFile)) != NULL);
  758.         break;
  759.  
  760.     case kStorageWin32MMFile:
  761.         A3Assert(0);    // not supported in this sample
  762.         break;
  763.  
  764.     case kStorageUnixFile:
  765.         if( dstFileMode == kQ3FileModeText )
  766.             aFile = fopen(pathName, "wt"); 
  767.         else
  768.             aFile = fopen(pathName, "wb"); 
  769.         A3Assert((dstStorage = Q3UnixStorage_New(aFile)) != NULL);
  770.         break;
  771.  
  772.     case kStorageUnixPath:
  773.         A3Assert((dstStorage = Q3UnixPathStorage_New(pathName)) != NULL);
  774.         break;
  775.     }
  776.  
  777.  
  778.     A3Assert((dstFileObject = Q3File_New()) != NULL);
  779.     A3Assert((aStatus = Q3File_SetStorage(dstFileObject, dstStorage)) == kQ3Success);
  780.     A3Assert((dstView = Q3View_New()) != NULL);
  781.     A3Assert((aStatus = Q3File_OpenWrite(dstFileObject, dstFileMode)) == kQ3Success);
  782.     A3Assert((aStatus = Q3View_StartWriting(dstView, dstFileObject)) == kQ3Success);
  783.     do
  784.     {
  785.         A3Assert((aStatus = Q3Object_Submit(gDocument->fModel, dstView)) == kQ3Success);
  786.         A3Assert((aViewStatus = Q3View_EndWriting(dstView)) != kQ3ViewStatusError);
  787.     } while (aViewStatus == kQ3ViewStatusRetraverse);
  788.     A3Assert((aStatus = Q3File_Close(dstFileObject)) == kQ3Success);
  789.  
  790.     /* Close the file system file as needed */
  791.     switch( storageMethod )
  792.     {
  793.     case kStorageWin32Handle:
  794.         CloseHandle( hFile );
  795.         break;
  796.     case kStorageWin32MMFile:
  797.         A3Assert(0); //unsupported in this sample
  798.         break;
  799.     case kStorageUnixFile:
  800.         fclose(aFile);
  801.         break;
  802.     case kStorageUnixPath:
  803.         // Nothing extra needs to be done 
  804.         break;
  805.     }
  806.  
  807.     A3Assert((aStatus = Q3Object_Dispose(dstFileObject)) == kQ3Success);
  808.     A3Assert((aStatus = Q3Object_Dispose(dstStorage)) == kQ3Success);
  809.  
  810. ExitSaveModelFile:
  811.     ;
  812. }
  813.  
  814.  
  815.  
  816. BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
  817. {
  818.         RECT    rChild, rParent;
  819.         int     wChild, hChild, wParent, hParent;
  820.         int     wScreen, hScreen, xNew, yNew;
  821.         HDC     hdc;
  822.  
  823.         // Get the Height and Width of the child window
  824.         GetWindowRect (hwndChild, &rChild);
  825.         wChild = rChild.right - rChild.left;
  826.         hChild = rChild.bottom - rChild.top;
  827.  
  828.         // Get the Height and Width of the parent window
  829.         GetWindowRect (hwndParent, &rParent);
  830.         wParent = rParent.right - rParent.left;
  831.         hParent = rParent.bottom - rParent.top;
  832.  
  833.         // Get the display limits
  834.         hdc = GetDC (hwndChild);
  835.         wScreen = GetDeviceCaps (hdc, HORZRES);
  836.         hScreen = GetDeviceCaps (hdc, VERTRES);
  837.         ReleaseDC (hwndChild, hdc);
  838.  
  839.         // Calculate new X position, then adjust for screen
  840.         xNew = rParent.left + ((wParent - wChild) /2);
  841.         if (xNew < 0) {
  842.                 xNew = 0;
  843.         } else if ((xNew+wChild) > wScreen) {
  844.                 xNew = wScreen - wChild;
  845.         }
  846.  
  847.         // Calculate new Y position, then adjust for screen
  848.         yNew = rParent.top  + ((hParent - hChild) /2);
  849.         if (yNew < 0) {
  850.                 yNew = 0;
  851.         } else if ((yNew+hChild) > hScreen) {
  852.                 yNew = hScreen - hChild;
  853.         }
  854.  
  855.         // Set it, and return
  856.         return SetWindowPos (hwndChild, NULL,
  857.                 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
  858. }
  859.  
  860.  
  861. // About box callback
  862. LRESULT CALLBACK About(
  863.                 HWND hDlg,           // window handle of the dialog box
  864.                 UINT message,        // type of message
  865.                 WPARAM uParam,       // message-specific information
  866.                 LPARAM lParam)
  867. {
  868.         static  HFONT hfontDlg;
  869.         LPSTR   lpVersion;
  870.         DWORD   dwVerInfoSize;
  871.         DWORD   dwVerHnd;
  872.         UINT    uVersionLen;
  873.         WORD    wRootLen;
  874.         BOOL    bRetCode;
  875.         int     i;
  876.         char    szFullPath[256];
  877.         char    szResult[256];
  878.         char    szGetName[256];
  879.  
  880.         switch (message) {
  881.                 case WM_INITDIALOG:  // message: initialize dialog box
  882.                         // Center the dialog over the application window
  883.                         CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
  884.  
  885.                         // Get version information from the application
  886.                         GetModuleFileName (hInst, szFullPath, sizeof(szFullPath));
  887.                         dwVerInfoSize = GetFileVersionInfoSize(szFullPath, &dwVerHnd);
  888.                         if (dwVerInfoSize) {
  889.                                 // If we were able to get the information, process it:
  890.                                 LPSTR   lpstrVffInfo;
  891.                                 HANDLE  hMem;
  892.                                 hMem = GlobalAlloc(GMEM_MOVEABLE, dwVerInfoSize);
  893.                                 lpstrVffInfo  = GlobalLock(hMem);
  894.                                 GetFileVersionInfo(szFullPath, dwVerHnd, dwVerInfoSize, lpstrVffInfo);
  895.                                 lstrcpy(szGetName, "\\StringFileInfo\\040904e4\\");
  896.                                 wRootLen = lstrlen(szGetName);
  897.  
  898.                                 // Walk through the dialog items that we want to replace:
  899.                                 for (i = IDC_FILEDESCRIPTION; i <= IDC_LEGALTRADEMARKS; i++) {
  900.                                         GetDlgItemText(hDlg, i, szResult, sizeof(szResult));
  901.                                         szGetName[wRootLen] = (char)0;
  902.                                         lstrcat (szGetName, szResult);
  903.                                         uVersionLen   = 0;
  904.                                         lpVersion     = NULL;
  905.                                         bRetCode      =  VerQueryValue((LPVOID)lpstrVffInfo,
  906.                                                 (LPSTR)szGetName,
  907.                                                 (LPVOID)&lpVersion,
  908.                                                 (LPDWORD)&uVersionLen); // For MIPS strictness
  909.  
  910.                                         if ( bRetCode && uVersionLen && lpVersion) {
  911.                                                 // Replace dialog item text with version info
  912.                                                 lstrcpy(szResult, lpVersion);
  913.                                                 SetDlgItemText(hDlg, i, szResult);
  914.                                         }
  915.                                 }
  916.  
  917.                                 GlobalUnlock(hMem);
  918.                                 GlobalFree(hMem);
  919.                         } // if (dwVerInfoSize)
  920.                         return (TRUE);
  921.  
  922.                 case WM_COMMAND:                      // message: received a command
  923.                         if (LOWORD(uParam) == IDOK        // "OK" box selected?
  924.                         || LOWORD(uParam) == IDCANCEL) {  // System menu close command?
  925.                                 EndDialog(hDlg, TRUE);        // Exit the dialog
  926.                                 DeleteObject (hfontDlg);
  927.                                 return (TRUE);
  928.                         }
  929.                         break;
  930.         }
  931.         return (FALSE); // Didn't process the message
  932. }
  933.  
  934.  
  935. BOOL InitDocumentData( DocumentPtr theDocument, HWND inWindow ) 
  936. {
  937.     RECT                aWinRect;
  938.     
  939.     theDocument->fWindow = inWindow;
  940.     (void) GetClientRect(inWindow, (LPRECT)&aWinRect);
  941.     theDocument->fWidth = aWinRect.right - aWinRect.left;
  942.     theDocument->fHeight = aWinRect.bottom - aWinRect.top;
  943.  
  944.     // sets up the 3d data for the scene
  945.     // Create view for QuickDraw 3D
  946.     theDocument->fView = MyNewView( theDocument ) ;
  947.     if( NULL == theDocument->fView )
  948.         return FALSE;
  949.  
  950.     // the main display group
  951.     if( NULL == theDocument->fModel )
  952.         theDocument->fModel = MyNewModel() ;
  953.     if( NULL == theDocument->fModel )
  954.         return FALSE;
  955.     
  956.     pvCamera_Fit(theDocument);
  957.  
  958.     // the drawing styles:
  959.     theDocument->fInterpolation = Q3InterpolationStyle_New(kQ3InterpolationStyleVertex) ;
  960.     if( NULL == theDocument->fInterpolation )
  961.         return FALSE;
  962.  
  963.     theDocument->fBackFacing = Q3BackfacingStyle_New(kQ3BackfacingStyleRemove ) ;
  964.     if( NULL == theDocument->fBackFacing )
  965.         return FALSE;
  966.     
  967.     theDocument->fFillStyle = Q3FillStyle_New(kQ3FillStyleFilled ) ;
  968.     if( NULL == theDocument->fFillStyle )
  969.         return FALSE;
  970.  
  971.     theDocument->fIllumination = Q3PhongIllumination_New();
  972.     if( NULL == theDocument->fIllumination )
  973.         return FALSE;
  974.  
  975.     // set the rotation matrix the identity matrix
  976.     Q3Matrix4x4_SetIdentity(&theDocument->fRotation);
  977.  
  978.     return TRUE;
  979. }
  980.  
  981. void DisposeDocumentData( DocumentPtr theDocument)
  982. {
  983.     if( theDocument == NULL )
  984.         return;
  985.     DisposeRenderingData( theDocument);
  986.     if( theDocument->fModel )
  987.     {
  988.         Q3Object_Dispose(theDocument->fModel) ;                // object in the scene being modelled
  989.         theDocument->fModel = NULL;
  990.     }
  991. }
  992.  
  993. void DisposeRenderingData( DocumentPtr theDocument)
  994. {    
  995.     if( theDocument == NULL )
  996.         return;
  997.     if( theDocument->fView )
  998.         Q3Object_Dispose(theDocument->fView) ;                // the view for the scene
  999.     if( kQ3DrawContextTypePixmap == theDocument->drawcontextType)
  1000.     {
  1001.         if( NULL != theDocument->fBitmap )
  1002.             DeleteObject(theDocument->fBitmap);
  1003.         if( NULL != theDocument->fMemoryDC ) 
  1004.             DeleteDC(theDocument->fMemoryDC);
  1005.     }
  1006.     if( theDocument->fInterpolation )
  1007.         Q3Object_Dispose(theDocument->fInterpolation) ;        // interpolation style used when rendering
  1008.     if( theDocument->fBackFacing )
  1009.         Q3Object_Dispose(theDocument->fBackFacing) ;        // whether to draw shapes that face away from the camera
  1010.     if( theDocument->fFillStyle )
  1011.         Q3Object_Dispose(theDocument->fFillStyle) ;            // whether drawn as solid filled object or decomposed to components
  1012.     if( theDocument->fIllumination )
  1013.         Q3Object_Dispose(theDocument->fIllumination) ;
  1014. }
  1015.  
  1016. //-----------------------------------------------------------------------------
  1017. // 
  1018.  
  1019. TQ3Status DocumentDraw3DData( DocumentPtr theDocument )
  1020. {
  1021.     int fps;
  1022.     if( kQ3Success == Q3View_StartRendering(theDocument->fView ) )    
  1023.         do {    
  1024.             Q3Shader_Submit( theDocument->fIllumination, theDocument->fView );    
  1025.             Q3Style_Submit( theDocument->fInterpolation, theDocument->fView );    
  1026.             Q3Style_Submit( theDocument->fBackFacing, theDocument->fView );    
  1027.             Q3Style_Submit( theDocument->fFillStyle, theDocument->fView );    
  1028.             Q3MatrixTransform_Submit( &theDocument->fRotation, theDocument->fView );    
  1029.             Q3DisplayGroup_Submit( theDocument->fModel, theDocument->fView );    
  1030.         } while (Q3View_EndRendering(theDocument->fView) == kQ3ViewStatusRetraverse );    
  1031.  
  1032.     /* must manually blit from the pixmap draw context */
  1033.     if( kQ3DrawContextTypePixmap == theDocument->drawcontextType)
  1034.     {
  1035.     RECT            aWinRect;
  1036.     BOOL            aResult;
  1037.     HDC                hdc;
  1038.         aResult = GetClientRect(theDocument->fWindow, (LPRECT)&aWinRect);
  1039.         hdc = GetDC(theDocument->fWindow);
  1040.         BitBlt(hdc, 0, 0, theDocument->fWidth, theDocument->fHeight,    
  1041.                 theDocument->fMemoryDC, 0, 0, SRCCOPY);                    
  1042.         GdiFlush();    
  1043.         ReleaseDC(theDocument->fWindow, hdc);                
  1044.     }
  1045.     
  1046.     fps = Speedometer_ClockFrame();
  1047.  
  1048.     /* display frame rate */
  1049.     if ( GetAsyncKeyState( VK_SHIFT ) )
  1050.     {
  1051.         HDC                hdc;
  1052.         char string[25];
  1053.         sprintf( string, "fps: %i", fps );
  1054.         hdc = GetDC(theDocument->fWindow);
  1055.         TextOut( hdc, 0, 0, string, strlen(string) ); 
  1056.     }
  1057.  
  1058.     return kQ3Success ;
  1059. }
  1060.  
  1061. /* Speedometer_ClockFrame
  1062.  * call this routine once per frame, it will return an averaged frames per second value.
  1063.  
  1064.  */
  1065. int Speedometer_ClockFrame( void )
  1066. {
  1067. #define NUMDELTAS 25
  1068.     DWORD    timeNow;
  1069.     DWORD    aveDelta = 0;
  1070.     static DWORD timePrevious = 0;
  1071.     static DWORD deltas[NUMDELTAS] = { 0 };
  1072.     static int nextDelta = 0;
  1073.     int fps, i;
  1074.  
  1075.  
  1076.     if( 0 == timePrevious  )
  1077.         timePrevious = GetTickCount();
  1078.     timeNow =  GetTickCount();
  1079.     deltas[nextDelta] = (timeNow-timePrevious);
  1080.     
  1081.     nextDelta++;
  1082.     if( nextDelta >= NUMDELTAS )
  1083.         nextDelta = 0;
  1084.     
  1085.     for( i = 0; i < NUMDELTAS; i++ )
  1086.         aveDelta += deltas[i];
  1087.     aveDelta /= NUMDELTAS;
  1088.     
  1089.     if( 0 == aveDelta  )
  1090.         aveDelta = 1;
  1091.  
  1092.     /* calculate frames per second */
  1093.     fps = 1000/aveDelta;
  1094.     
  1095.     timePrevious = timeNow;
  1096.     
  1097.     return fps;
  1098. }
  1099.  
  1100. TQ3Status DocumentNewWindowSize(DocumentPtr theDocument, unsigned long width, unsigned long height)
  1101. {
  1102.     TQ3Status    aStatus;
  1103.  
  1104.     aStatus = MyResizeView( theDocument, width, height);
  1105.  
  1106.     pvCamera_Fit(gDocument);
  1107.     
  1108.     return aStatus;
  1109. }
  1110.  
  1111.